home *** CD-ROM | disk | FTP | other *** search
/ BCI NET 2 / BCI NET 2.iso / archives / programming / source / tracker-4.13.lha / tracker / open.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-02-15  |  10.4 KB  |  538 lines

  1. /* open.c 
  2.     vi:ts=3 sw=3:
  3.  */
  4.  
  5. /* Magic open file: path lookup and transparent decompression */
  6.  
  7. /* $Id: open.c,v 4.10 1995/02/08 13:14:56 espie Exp $ 
  8.  * $Log: open.c,v $
  9.  * Revision 4.10  1995/02/08  13:14:56  espie
  10.  * *** empty log message ***
  11.  *
  12.  * Revision 4.10  1995/02/08  13:14:56  espie
  13.  * *** empty log message ***
  14.  *
  15.  * Revision 4.9  1995/02/01  20:41:45  espie
  16.  * Added color.
  17.  *
  18.  * Revision 4.9  1995/02/01  20:41:45  espie
  19.  * Added color.
  20.  *
  21.  * Revision 4.8  1995/02/01  16:39:04  espie
  22.  * Cleaned up rewind stuff.
  23.  * Fixed serious bug with read_file.
  24.  *
  25.  * Revision 4.8  1995/02/01  16:39:04  espie
  26.  * Cleaned up rewind stuff.
  27.  * Fixed serious bug with read_file.
  28.  *
  29.  * Revision 4.7  1995/01/30  18:15:01  espie
  30.  * Implemented buffer for open_file and such !
  31.  *
  32.  *
  33.  * Revision 4.2  1994/07/04  14:00:06  espie
  34.  * External compression methods.
  35.  * A little more abstract, should work better
  36.  * Better amiga patterns.
  37.  * Amiga support.
  38.  * Added gzip/shorten.
  39.  * restore stty.
  40.  *
  41.  * Revision 1.5  1992/11/01  13:10:06  espie
  42.  * Cleaned up path handler, and some more bugs.
  43.  * Check for size now.
  44.  * Added path support. Transparent interface. We look up through the file
  45.  * list, which is small anyway.
  46.  */
  47.  
  48. #include "defs.h"
  49.  
  50. #include <ctype.h>
  51.  
  52. #include "extern.h"
  53.  
  54. ID("$Id: open.c,v 4.10 1995/02/08 13:14:56 espie Exp $")
  55.  
  56.  
  57. /* forward declarations */
  58. LOCAL struct exfile *do_open(struct exfile *file, char *fname, char *path);
  59.  
  60.  
  61.  
  62. /***
  63.  
  64.     Stuff for compression methods 
  65.  
  66.  ***/
  67.  
  68. /* Max buffer length for reading compression methods */
  69. #define MAX_LENGTH 90
  70.  
  71.  
  72. /* automaton */
  73. #define END_OF_LINE 0
  74. #define BEGIN_OF_LINE 1
  75. #define IN_SPEC 2
  76. #define BEGIN_OF_COMMAND 3
  77. #define IN_COMMAND 4
  78.  
  79.  
  80. LOCAL void init_compression P((void));
  81. LOCAL void (*INIT)P((void)) = init_compression;
  82. extern int error;
  83.  
  84.  
  85.  
  86. /* extended file structure:
  87.  *        designed to be able to rewind pipes on a small length
  88.  *     (BUFSIZE) in order to be able to retry lots of formats
  89.  *        for cheap
  90.  */
  91. #define BUFSIZE 15000
  92. struct exfile
  93.    {
  94.    FILE *handle;                            /* the real Mc Coy */
  95.     unsigned char buffer[BUFSIZE];    /* we buffer only the file beginning */
  96.     int length;                                /* the length read in the buffer */
  97.     int pos;                                    /* current pos in the buffer */
  98.  
  99.         /* OO methods */
  100.    void (*close)P((struct exfile *f));    
  101.    void (*rewind)P((struct exfile *f));
  102.     int (*read)P((void *ptr, int size, int nitems, struct exfile *f));
  103.    int (*getcar)P((struct exfile *f));
  104.    int (*tell)P((struct exfile *f));
  105.  
  106.         /* kludge to reopen file */
  107.     char *name;
  108.     char *path;
  109.    };
  110.  
  111. /* the methods for buffered files */
  112. LOCAL int do_getchar(f)
  113. struct exfile *f;
  114.    {
  115.    int c;
  116.  
  117.     if (f->pos < BUFSIZE)
  118.         {
  119.         if (f->pos >= f->length)
  120.             {
  121.             error = FILE_TOO_SHORT;
  122.             return EOF;
  123.             }
  124.         else
  125.             return f->buffer[f->pos++];
  126.         }
  127.    if ((c = fgetc(f->handle)) == EOF)
  128.       error = FILE_TOO_SHORT;
  129.    else
  130.       f->pos++;
  131.    return c;
  132.    }
  133.  
  134. LOCAL int do_read(p, s, n, f)
  135. void *p;
  136. int s, n;
  137. struct exfile *f;
  138.     {
  139.     int total = s * n;
  140.     if (f->pos < BUFSIZE)
  141.         {
  142.         int remaining = f->length - f->pos;
  143.         if (remaining >= total)
  144.             {
  145.             memcpy(p, &(f->buffer[f->pos]), total);
  146.             f->pos += total;
  147.             return n;
  148.             }
  149.         else
  150.             {
  151.             memcpy(p, &(f->buffer[f->pos]), remaining);
  152.             total = remaining + 
  153.                     fread((char *)p+remaining, 1, total - remaining, f->handle);
  154.             f->pos += total;
  155.             return total/s;
  156.             }
  157.         }
  158.     else
  159.         {
  160.         total = fread(p, s, n, f->handle);
  161.         f->pos += total * s;
  162.         return total;
  163.         }
  164.     }
  165.  
  166.  
  167. LOCAL void do_rewind(f)
  168. struct exfile *f;
  169.     {
  170.     if (f->pos <= f->length)
  171.         f->pos = 0;
  172.     else
  173.         {
  174.         (*f->close)(f);
  175.         f = do_open(f, f->name, f->path);
  176.         }
  177.     }
  178.  
  179. LOCAL int do_tell(f)
  180. struct exfile *f;
  181.    {
  182.    return f->pos;
  183.    }
  184.  
  185. LOCAL void do_pclose(f)
  186. struct exfile *f;
  187.    {
  188.    pclose(f->handle);
  189.    }
  190.  
  191. LOCAL void do_fclose(f)
  192. struct exfile *f;
  193.    {
  194.    fclose(f->handle);
  195.    }
  196.  
  197. LOCAL struct exfile *init_buffered(f)
  198. struct exfile *f;
  199.     {
  200.     f->length = fread(f->buffer, 1, BUFSIZE, f->handle);
  201.     f->getcar = do_getchar;
  202.     f->tell = do_tell;
  203.     f->read = do_read;
  204.     f->rewind = do_rewind;
  205.     f->pos = 0;
  206.     return f;
  207.     }
  208.   
  209. /* compression methods we do know about.
  210.  * Important restriction: for the time being, the output
  211.  * must be a single module.
  212.  */
  213.  
  214. struct compression_method
  215.    {
  216.    struct compression_method *next;
  217.    char *extension;
  218.    char *command;
  219.    };
  220.  
  221. struct compression_method *read_method(f)
  222. FILE *f;
  223.    {
  224.    static char buffer[MAX_LENGTH + 1];
  225.    
  226.    while (fgets(buffer, MAX_LENGTH, f))
  227.       {
  228.       int state = BEGIN_OF_LINE;
  229.       int start, i;
  230.       char *spec = NULL, *command = NULL;
  231.       
  232.       for (i = 0; state != END_OF_LINE; i++)
  233.          {
  234.          switch(state)
  235.             {
  236.          case BEGIN_OF_LINE:
  237.             switch(buffer[i])
  238.                {
  239.             case ' ':
  240.             case '\t':
  241.                break;
  242.             case 0:
  243.             case '\n':
  244.             case '#':
  245.                state = END_OF_LINE;
  246.                break;
  247.             default:
  248.                start = i;
  249.                state = IN_SPEC;
  250.                }
  251.             break;
  252.          case IN_SPEC:
  253.             switch(buffer[i])
  254.                {
  255.             case ' ':
  256.             case '\t':
  257.                spec = malloc(i - start + 1);
  258.                strncpy(spec, buffer + start, i - start);
  259.                spec[i - start] = 0;
  260.                state = BEGIN_OF_COMMAND;
  261.                break;
  262.             case 0:
  263.             case '\n':
  264.                state = END_OF_LINE;
  265.                break;
  266.             default:
  267.                break;
  268.                }
  269.             break;
  270.          case BEGIN_OF_COMMAND:
  271.             switch (buffer[i])
  272.                {
  273.             case ' ':
  274.             case '\t':
  275.                break;
  276.             case 0:
  277.             case '\n':
  278.                state = END_OF_LINE;
  279.                free(spec);
  280.                break;
  281.             default:
  282.                state = IN_COMMAND;
  283.                start = i;
  284.                }
  285.             break;
  286.          case IN_COMMAND:
  287.             switch (buffer[i])
  288.                {
  289.             case 0:
  290.             case '\n':
  291.                command = malloc(i - start + 1);
  292.                strncpy(command, buffer + start, i - start);
  293.                command[i-start] = 0;
  294.                state = END_OF_LINE;
  295.             default:
  296.                break;
  297.                }
  298.             }
  299.          }      
  300.       if (command && spec)
  301.          {
  302.          struct compression_method *new;
  303.          
  304.          new = malloc(sizeof(struct compression_method));
  305.          new->next = 0;
  306.          new->extension = spec;
  307.          new->command = command;
  308.          return new;
  309.          }
  310.       }
  311.    return 0;
  312.    }
  313.       
  314.  
  315. LOCAL struct compression_method **read_methods(previous, f)
  316. struct compression_method **previous;
  317. FILE *f;
  318.    {
  319.    struct compression_method *method;
  320.    
  321.    if (f)
  322.       {
  323.       while (method = read_method(f))
  324.          {
  325.          *previous = method;
  326.          previous = &(method->next);
  327.          }
  328.       fclose(f);
  329.       }
  330.    return previous;
  331.    }
  332.       
  333.  
  334. LOCAL struct compression_method *comp_list;
  335.  
  336. LOCAL void init_compression()
  337.    {
  338.    char *fname;
  339.    FILE *f;
  340.    struct compression_method **previous;
  341.  
  342.    f = 0;
  343.    fname = getenv("TRACKER_COMPRESSION");
  344.    if (fname)
  345.       f = fopen(fname, "r");
  346.    if (!f)
  347.       {
  348.       fname = COMPRESSION_FILE;
  349.       f = fopen(fname, "r");
  350.       }
  351.    previous = read_methods(&comp_list, f);
  352.    }
  353.       
  354. /***
  355.  
  356.    Handling extensions.
  357.  
  358.  ***/
  359.  
  360. LOCAL int check_ext(s, ext)
  361. char *s, *ext;
  362.    {
  363.    int ext_len, s_len;
  364.    char *c;
  365.  
  366.    ext_len = strlen(ext);
  367.    s_len = strlen(s);
  368.    if (s_len < ext_len)
  369.       return FALSE;
  370.    for (c = s + s_len - ext_len; *c; c++, ext++)
  371.       if (tolower(*c) != tolower(*ext))
  372.          return FALSE;
  373.    return TRUE;
  374.    }
  375.  
  376. LOCAL int exist_file(fname)
  377. char *fname;
  378.    {
  379.    FILE *temp;
  380.  
  381.    temp = fopen(fname, READ_ONLY);
  382.    if (temp)
  383.       {
  384.       fclose(temp);
  385.       return TRUE;
  386.       }
  387.    else
  388.       return FALSE;
  389.    }
  390.  
  391. #ifndef MAXPATHLEN
  392. #define MAXPATHLEN 350
  393. #endif
  394.  
  395. /* note that find_file returns a STATIC value */
  396.  
  397. LOCAL char *find_file(fname, path)
  398. char *fname;
  399. char *path;
  400.    {
  401.    char *sep;
  402.    static char buffer[MAXPATHLEN];
  403.    int len;
  404.  
  405.       /* first, check the current directory */
  406.    if (exist_file(fname))
  407.       return fname;
  408.    while(path)
  409.       {
  410.       sep = strchr(path, ':');
  411.       if (sep)
  412.          len = sep - path;
  413.       else
  414.          len = strlen(path);
  415.       if (len < MAXPATHLEN)
  416.          {
  417.          strncpy(buffer, path, len);
  418.          buffer[len] = '/';
  419.          if (len + strlen(fname) < MAXPATHLEN - 5)
  420.             {
  421.             strcpy(buffer + len + 1, fname);
  422.             puts(buffer);
  423.             if (exist_file(buffer))
  424.                return buffer;
  425.             }
  426.          }
  427.       if (sep)
  428.          path = sep + 1;
  429.       else
  430.             return NULL;
  431.       }
  432.     return NULL;
  433.    }
  434.  
  435. /* opening a file is bigger than it seems (much bigger) */
  436. LOCAL struct exfile *do_open(file, fname, path)
  437. struct exfile *file;
  438. char *fname;
  439. char *path;
  440.    {
  441.    struct compression_method *comp;
  442.  
  443.    INIT_ONCE;
  444.     
  445.     file->name = fname;
  446.     file->path = path;
  447.  
  448.    fname = find_file(fname, path);
  449.    if (!fname)
  450.       goto not_opened;
  451.          /* check for extension */
  452.    for (comp = comp_list; comp; comp = comp->next)
  453.       if (check_ext(fname, comp->extension))
  454.          {
  455.          char *pipe;
  456.          
  457.          pipe = malloc(strlen(comp->command) + strlen(fname) + 25);
  458.          if (!pipe)
  459.             goto not_opened;
  460.  
  461.          sprintf(pipe, comp->command, fname);
  462.          file->close = do_pclose;
  463.          file->handle = popen(pipe, READ_ONLY);
  464.          free(pipe);
  465.          if (file->handle)
  466.             return init_buffered(file);
  467.          else
  468.             goto not_opened;
  469.          }
  470.    file->close = do_fclose;
  471.    if (file->handle = fopen(fname, READ_ONLY))
  472.       return init_buffered(file);
  473.  
  474. not_opened:
  475.    free(file);
  476.    return NULL;
  477.    }
  478.  
  479.  
  480.  
  481.  
  482. /*** 
  483.  
  484.     the actual calls to handle a file 
  485.  
  486.  ***/
  487.  
  488. int getc_file(f)
  489. struct exfile *f;
  490.    {
  491.    return (*f->getcar)(f);
  492.    }
  493.  
  494. int read_file(p, s, n, f)
  495. void *p;
  496. int s, n;
  497. struct exfile *f;
  498.     {
  499.     return (*f->read)(p, s, n, f);
  500.     }
  501.  
  502. int tell_file(f)
  503. struct exfile *f;
  504.    {
  505.    return (*f->tell)(f);
  506.    }
  507.  
  508. void rewind_file(f)
  509. struct exfile *f;
  510.     {
  511.     (*f->rewind)(f);
  512.     }
  513.  
  514. struct exfile *open_file(fname, mode, path)
  515. char *fname;
  516. char *mode; /* right now, only mode "r" is supported */
  517. char *path; 
  518.     {
  519.     struct exfile *new;
  520.  
  521.    if (mode[0] != 'r' || mode[1] != 0)
  522.       return NULL;
  523.     new = (struct exfile *)malloc(sizeof(struct exfile));
  524.    if (new)
  525.         return do_open(new, fname, path);
  526.     else
  527.       return NULL;
  528.     }
  529.  
  530.  
  531. void close_file(file)
  532. struct exfile *file;
  533.    {
  534.    (*file->close)(file);
  535.    free(file);
  536.    }
  537.  
  538.